<?php

require_once(BASE_CODEVAULT_DIR."/lib/doctrine/lib/Doctrine/Pager/Layout.php");

class Pagenation{
    private $pager;
    private $pager_range;
    private $pager_layout;
    private $url;
    private $isDebugMode;
    private $perPage;
    private $perChuk;
    private $pageStyle;
    public $Warnings;
    const PageKey = "page";

    function __construct($url, $isDebugMode = false, $perPage = 20, $perChuk = 5, $pageStyle = "Sliding"){
        $this->url = $url;
        $this->isDebugMode = $isDebugMode;
        $this->perPage = $perPage;
        $this->perChuk = $perChuk;
        $this->pageStyle = $pageStyle;
    }

    public function ExecuteQuery($query){
        $this->pager = new Doctrine_Pager($query, $this->CurrentPage(), $this->perPage);
        $this->pager_range = $this->pager->getRange($this->pageStyle, array('chunk' => $this->perChuk));
        $this->pager_layout = new PagerLayoutWithArrows($this->pager, $this->pager_range, $this->url.'/?'.self::PageKey.'={%page_number}');
        $this->pager_layout->setFirstTemplate('<li class="first_link"><a href="{%url}">&laquo;</a></li>');
        $this->pager_layout->setBackTemplate('<li class="back_link"><a href="{%url}">&lsaquo;</a></li>');
        $this->pager_layout->setSelectedTemplate('<li class="current_link">{%page}</li>');
        $this->pager_layout->setTemplate('<li class="link"><a href="{%url}">{%page}</a></li>');
        $this->pager_layout->setSeparatorTemplate('<li class="separator">|</li>');
        $this->pager_layout->setNextTemplate('<li class="next_link"><a href="{%url}">&rsaquo;</a></li>');
        $this->pager_layout->setLastTemplate('<li class="last_link"><a href="{%url}">&raquo;</a></li>');
    }

    public function Execute($tableName, $allowRequestParameters = false, $parameters = array(), $allowedParameters = null){
        $this->Warnings = Array();

        $table = Doctrine::getTable($tableName);

        $queryAnd = Array();
        $queryParameters = Array();

        if(!empty($_GET) && $allowRequestParameters){
            $requestParameters = Arr::fluent($_GET)->trim()->c;
            $parameters = array_merge($parameters, $requestParameters);
        }

        foreach($parameters as $key => $value){
            if($key == self::PageKey){
                continue;
            }

            if(!$this->ContainsKey($allowedParameters, $key)){
                $this->WarningAdd("Key '".$key."' is not in allowed field list!");
                continue;
            }

            $definition = $table->getDefinitionOf($key);

            if (!empty($definition)){
                $type = Arr::fluent($definition)->at('type');
                $v = is_array($value) ? $value : array($value);

                $queryOr = Array();
                foreach($v as $option){
                    if(empty($option)){
                        $filter = ' is null';
                    }
                    else{
                        switch($type){
                            case 'string':
                                $filter = ' LIKE ?';
                                $queryParameters[] = "%$option%";
                                break;
                            case 'timestamp':
                                $filter = ' > ?';
                                $queryParameters[] = $option;
                                break;
                            default:
                                $filter = ' = ?';
                                $queryParameters[] = $option;
                                break;
                        }
                    }
                    $queryOr[] = $key.$filter;
                }
                $queryAnd[] = "(".implode(" OR ", $queryOr).")";
            }
            else{
                $this->WarningAdd("Table '".$tableName."' has no field with name '".$key."'!");
            }
        }

        $query = null;
        if(empty($queryAnd)){
            $query = $table->createQuery();
        }else{
            $queryText = implode(" AND ", $queryAnd);
            $query = Doctrine_Query::create()->from($tableName)->where($queryText, $queryParameters);
        }

        if($this->isDebugMode){
            $debugInfo["parameters"] = $parameters;
            $debugInfo["query"] = $query->getSqlQuery();
            $di["PAGENATION_DEBUG_INFO"][] = $debugInfo;
            echo "<pre>";
            print_r($di);
            echo "</pre>";
        }

        $this->ExecuteQuery($query);
    }

    public function GetItems($hydrationMode = Doctrine::HYDRATE_ARRAY){
        $results = $this->pager->execute(array(), $hydrationMode);
        if($this->isDebugMode){
            $debugInfo["results"] = $results;
            $di["PAGENATION_DEBUG_INFO"][] = $debugInfo;
            echo "<pre>";
            print_r($di);
            echo "</pre>";
        }
        return $results;
    }

    public function GetPager(){
        return $this->pager_layout->display();
    }

    public function WarningAdd($text){
        if($this->isDebugMode){
            $this->Warnings[] = $text;
        }
    }

    public function CurrentPage(){
        return empty($_GET['page']) ? 1 : $_GET['page'];
    }

    private function ContainsKey($array, $key){
        if(empty($array)){
            return true;
        }
        foreach($array as $item){
            if(strtolower($item) == strtolower($key)){
                return true;
            }
        }
        return false;
    }
}

//region custom pager

class PagerLayoutWithArrows extends Doctrine_Pager_Layout {
    //region Custom templates

    private $_template_back;
    private $_template_first;
    private $_template_next;
    private $_template_last;

    public function setBackTemplate($template){
        $this->_template_back = $template;
    }

    public function setFirstTemplate($template){
        $this->_template_first = $template;
    }

    public function setNextTemplate($template){
        $this->_template_next = $template;
    }

    public function setLastTemplate($template){
        $this->_template_last = $template;
    }

    protected function _parseCustomTemplate($template, $options = array())
    {
        $str = $this->_parseMaskReplacements($template);
        $replacements = $this->_parseReplacementsTemplate($options);

        return strtr($str, $replacements);
    }

    //endregion Custom templates

    public function display( $options = array(), $return = true )
    {
        $pager = $this->getPager();

        $str = '';

        if(!empty($this->_template_first)){
            $options['page_number'] = $pager->getFirstPage();
            $str .= $this->_parseCustomTemplate($this->_template_first, $options);
        }
        if(!empty($this->_template_back)){
            $options['page_number'] = $pager->getPreviousPage();
            $str .= $this->_parseCustomTemplate($this->_template_back, $options);
        }

        $range = $this->getPagerRange()->rangeAroundPage();
        for ($i = 0, $l = count($range); $i < $l; $i++) {
            $options['page_number'] = $range[$i];

            $str .= $this->processPage($options);

            if ($i < $l - 1) {
                $str .= $this->getSeparatorTemplate();
            }
        }

        if(!empty($this->_template_next)){
            $options['page_number'] = $pager->getNextPage();
            $str .= $this->_parseCustomTemplate($this->_template_next, $options);
        }
        if(!empty($this->_template_last)){
            $options['page_number'] = $pager->getLastPage();
            $str .= $this->_parseCustomTemplate($this->_template_last, $options);
        }

        $str = "<div class='pagenation'><ul>".$str."</ul></div>";

        if ($return) {
            return $str;
        }

        echo $str;
    }
}

//endregion custom pager